/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
 * secGear is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */


#include <fstream>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <any>
#include <variant>

#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include "common.h"
#include "kv_t.h"
using namespace std;

#define TA_HELLO_WORLD        "secgear hello world!"
#define BUF_MAX 32

const uint8_t userkey[16] = {   // AES密钥生成参数
    '1', '2', '3', '4',
    '5', '6', '7', '8',
    '9', '0', '1', '2',
    '3', '4', '5', '6'
};
// 分组加密
uint8_t aes_in[16] = {0}, aes_out[16] = {0};    

// 加解密秘钥
AES_KEY encrypt_key, decrypt_key;   

vector<KEY> KeyVec;                 // 键值对列表
list<KEY> KeyList;                  
hash<string> strHash;               // 字符串hash函数

int get_string(char *buf)
{
    strncpy(buf, TA_HELLO_WORLD, strlen(TA_HELLO_WORLD) + 1);
    return 0;
}
// 加密
void AES_Encrypt(KEY &Key)
{
    uint8_t *value = (uint8_t *)Key.val_ptr;            // 获取value值
    AES_set_encrypt_key(userkey, 128, &encrypt_key);    // 生成128bit加密秘钥
    for (size_t i = 0;i < Key.val_size;i+=16) {
        memcpy(aes_in, value+i, 16);            // 取16字节
        AES_ecb_encrypt(aes_in, aes_out, &encrypt_key, AES_ENCRYPT);    // 加密
        memcpy(value+i, aes_out, 16);           // 拷贝回去
    }
}
// 解密
void AES_Decrypt(KEY Key, uint8_t *buf)
{
    uint8_t *value = (uint8_t *)Key.val_ptr;
    AES_set_decrypt_key(userkey, 128, &decrypt_key);    // 生成128bit解密密钥
    for (size_t i = 0;i < Key.val_size;i+=16) {
        memcpy(aes_in, value+i,16);             // 取16字节
        AES_ecb_encrypt(aes_in, aes_out, &decrypt_key, AES_DECRYPT);    // 解密
        memcpy(buf+i, aes_out, 16);             // 拷贝到buf
    }
}

int search_key(int key_val)
{
    for (int i = 0;i < KeyVec.size();i++) {
        if (KeyVec[i].key_val == key_val) {             // 查找到key
            return i;
        }
    }
    return -1;
}

/**
 * @param key_val 键信息
 * @param val_addr 值在不可信内存中的地址
 * @param val_len 值的长度
*/
int Set_KV(int key_val, uint64_t val_addr, size_t val_len)
{
    // 初始化键值对信息
    KEY Key;                                // 新建一个KEY变量
    Key.key_val = key_val;                  // 初始化key值
    Key.val_ptr = (uint8_t*)val_addr;       // 初始化value指针
    Key.val_size = val_len;                 // 值的长度
    
    // 计算hash值，实现完整性保护
    char *str = new char[VALUE_SIZE + 1];   // 转为char*
    memcpy(str, Key.val_ptr, val_len);                  
    string value_str = str;                 // 转为string

    Key.hash_value = strHash(value_str);    // 计算hash值
    
    // 对不可信内存中的value内容进行加密（AES-ECB模式）
    // AES_Encrypt(Key);

    // 是否已存在键相同的键值对映射
    int index = search_key(key_val);
    // 不存在
    if (index < 0) {
        // 将Key插入列表
        KeyVec.push_back(Key);
    } 
    else {
        KeyVec[index] = Key;
    }
    return 0;
}
/**
 * @param key_val 键信息
 * @param value_val 返回值
*/
int Get_KV(int key_val, uint8_t* value_val)
{
    // 查找键值对下标
    int index = search_key(key_val);
    if (index < 0) return -1;
 
    // 解密
    // AES_Decrypt(KeyVec[index], value_val);
    // 转为string计算hash
    char *str = new char[VALUE_SIZE + 1];       // 转为char*
    memcpy(str, value_val, KeyVec[index].val_size); 
    // 计算hash值 
    string value_str = str;      
    size_t hashval = strHash(value_str);              
    // 校验完整性
    if (KeyVec[index].hash_value != hashval) {
        memset(value_val, '0', KeyVec[index].val_size);
    }
    return 0;
}
/**
 * @param key_val 键信息
 * @return 是否删除成功
*/
int Delete_KV(int key_val)
{
    int index = search_key(key_val);
    if (index < 0) return -1;
    // 删除键为1的键值对并回收内存
    KeyVec.erase(KeyVec.begin() + index);
    // KeyVec.erase(remove(KeyVec.begin(), KeyVec.end(), Key));
    
    return 0;
}